`timescale 1ns / 1ns

module img_sche #(
    parameter [15:0] IMAGE_X = 16'd8,
    parameter [15:0] IMAGE_Y = 16'd8,
    parameter [15:0] STEP_X = 16'd8,
    parameter [15:0] STEP_Y = 16'd8
)
(
    input rst,
    input clk,
    input signed [15:0] x[2:0],
    input signed [15:0] y[2:0],
    // 深度值范围为整个unsigned short，只是直接用于比对
    input [15:0] z[2:0],
	input boot,
    output enable
);

localparam [15:0] RESO_X = IMAGE_X * STEP_X,
                  RESO_Y = IMAGE_Y * STEP_Y;

reg signed [15:0] xst, yst, xed, yed;
reg signed [15:0] xp, yp;
reg block_boot;
wire busy;

img_block block_inst(
    .rst(rst),
    .clk(clk),
    .x(x), .y(y), .z(z),
    .xst(xp), .yst(yp),
	.boot(block_boot),
    .busy(busy)
);

reg signed [15:0] xmin, xmax, ymin, ymax;

always @* begin
    xmin = (x[0] < x[1] ? (x[0] < x[2] ? x[0] : x[2]) : (x[1] < x[2] ? x[1] : x[2]));
    xmax = (x[0] > x[1] ? (x[0] > x[2] ? x[0] : x[2]) : (x[1] > x[2] ? x[1] : x[2]));
    ymin = (y[0] < y[1] ? (y[0] < y[2] ? y[0] : y[2]) : (y[1] < y[2] ? y[1] : y[2]));
    ymax = (y[0] > y[1] ? (y[0] > y[2] ? y[0] : y[2]) : (y[1] > y[2] ? y[1] : y[2]));
    xst = (xmin < 16'd0 ? 16'd0 : xmin);
    xed = (xmax > RESO_X ? RESO_X : xmax);
    yst = (ymin < 16'd0 ? 16'd0 : ymin);
    yed = (ymax > RESO_Y ? RESO_Y : ymax);
    xst[2:0] = 0;
    yst[2:0] = 0;
end

reg signed [31:0] a[2:0], b[2:0], c[2:0];// 这是不是也会变成wire?
reg [2:0] v;
reg valid;

always @* begin
    integer i, j;
    for (i = 0; i < 3; i = i + 1) begin
        j = (i + 1) % 3;
        a[i] = y[i] - y[j];
        b[i] = x[j] - x[i];
        c[i] = x[i] * y[j] - x[j] * y[i];
        v[i] = (a[i] * xp + b[i] * yp + c[i] <= 32'sd0) ||
               (a[i] * (xp + $signed(STEP_X) - 1) + b[i] * yp + c[i] <= 32'sd0) ||
               (a[i] * xp + b[i] * (yp + $signed(STEP_Y) - 1) + c[i] <= 32'sd0) ||
               (a[i] * (xp + $signed(STEP_X) - 1) + b[i] * (yp + $signed(STEP_Y) - 1) + c[i] <= 32'sd0);
    end
    valid = &v;
end

localparam [1:0] STATE_IDLE = 2'b00,
                 STATE_BOUND = 2'b01,
                 STATE_RUN = 2'b10,
                 STATE_WAIT = 2'b11;
reg [1:0] state;

assign enable = (state != STATE_IDLE);

always @(posedge clk or negedge rst) begin
    if (!rst) begin
        state <= STATE_IDLE;
    end
    else begin
        case (state)
            STATE_IDLE: begin
                if (boot) begin
                    state <= STATE_BOUND;
                end
            end
            STATE_BOUND: begin
                xp <= xst; yp <= yst;
                state <= STATE_RUN;
            end
            STATE_RUN: begin
                if (valid) begin
                    block_boot <= 1;
                    state <= STATE_WAIT;
                end
                else begin
                    if (xp + STEP_X >= xed) begin
                        if (yp + STEP_Y >= yed) begin
                            state <= STATE_IDLE;
                        end
                        else begin
                            xp <= xst;
                            yp <= yp + STEP_Y;
                        end
                    end
                    else begin
                        xp <= xp + STEP_X;
                    end
                end
            end
            STATE_WAIT: begin
                if (block_boot) begin
                    if (busy) block_boot <= 0;
                end
                else if (!busy) begin
                    state <= STATE_RUN;
                    if (xp + STEP_X >= xed) begin
                        if (yp + STEP_Y >= yed) begin
                            state <= STATE_IDLE;
                        end
                        else begin
                            xp <= xst;
                            yp <= yp + STEP_Y;
                        end
                    end
                    else begin
                        xp <= xp + STEP_X;
                    end
                end
            end
        endcase
    end
end

endmodule